package com.chenfan.mcn.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.vo.UserVO;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.ArchiveCodeCst;
import com.chenfan.mcn.constant.BillCodeCst;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.*;
import com.chenfan.mcn.event.EventPublisher;
import com.chenfan.mcn.event.OperateLogEvent;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.component.CodeGenerateHelper;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.service.MessageInfoService;
import com.chenfan.mcn.service.PlaceOnFileService;
import com.chenfan.mcn.service.StarArchivingCodeRuleService;
import com.chenfan.mcn.utils.BusinessAssert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @Author liuyang
 * @Date 2021/9/30
 * @Time 11:31
 * @Version V1.0
 **/
@Slf4j
@Service
public class PlaceOnFileServiceImpl implements PlaceOnFileService {

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private IncomeContactAgreementMapper icAgreementMapper;

    @Autowired
    private AnnualRebateApprovalMapper annualRebateApprovalMapper;

    @Autowired
    private PurchaseContractMapper purchaseContractMapper;

    @Autowired
    private YearFrameContractMapper yearFrameContractMapper;

    @Autowired
    private YearSupplementaryAgreementMapper yfAgreementMapper;

    @Autowired
    private StarRebateContractMapper starRebateContractMapper;

    @Autowired
    private MessageInfoService messageInfoService;

    @Autowired
    private StarArchivingCodeRuleService ruleService;

    @Autowired
    private StarPlatformInfoMapper starPlatformInfoMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void seal(String billCode, String archivingCode) {
        UserVO userVO= UserVoContextHolder.getUserVo();
        Long tenantId=Objects.nonNull(userVO)&&Objects.nonNull(userVO.getTenantId())?userVO.getTenantId():null;
        BusinessAssert.notBlank(billCode, McnErrorCode.BILL_CODE_NOT_NULL);
        BusinessAssert.notBlank(archivingCode, McnErrorCode.ARCHIVING_CODE_NOT_NULL);
        BusinessAssert.isTrue(messageInfoService.idempotentArchivingCode(billCode, archivingCode,tenantId), McnErrorCode.DUPLICATE_ARCHIVE_NUMBER);
        updateArchivingInfo(billCode, ArchivingStatusEnum.TO_BE_FILED, archivingCode);
    }

    @Override
    public void file(String billCode) {
        updateArchivingInfo(billCode, ArchivingStatusEnum.ARCHIVED, null);
    }

    @Override
    public String getArchiveCode(String billCode) {
        // 注意前缀开头是否存在包含关系
        if (isIncomeContractAgreement(billCode)) {
            return getArchiveCodeForIncomeContractAgreement(billCode);
        } else if (isIncomeContract(billCode)) {
            return getArchiveCodeForIncomeContract(billCode);
        } else if (isYearFrameContractAgreement(billCode)) {
            return this.getArchiveCodeForYearFrameContractAgreement(billCode);
        } else if (isYearFrameContract(billCode)) {
            return getArchiveCodeForYearFrameContract(billCode);
        } else if (isPurchaseContract(billCode) || isAnnualRebateApproval(billCode) || isStarRebateContract(billCode)) {
            return CodeGenerateHelper.getUniqueArchivingCode(ArchiveCodeCst.CFTG);
        }  else {
            throw new BusinessException(McnErrorCode.ILLEGAL_BILL_CODE);
        }
    }

    /**
     * 收入合同补充协议取归档编号
     * @param billCode
     * @return
     */
    private String getArchiveCodeForIncomeContractAgreement(String billCode) {
        IncomeContractAgreement entity = icAgreementMapper.selectOne(Wrappers.lambdaQuery(IncomeContractAgreement.class)
                .eq(IncomeContractAgreement::getAgreementCode, billCode)
                .eq(IncomeContractAgreement::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "收入合同补充协议不存在");
        IncomeContract incomeContract = incomeContractMapper.selectById(entity.getIncomeContractId());
        BusinessAssert.notNull(incomeContract, McnErrorCode.DATA_NOT_FOUND, "收入合同不存在");
        BusinessAssert.notBlank(incomeContract.getArchivingCode(), McnErrorCode.BUSINESS_ERROR, "收入合同无归档编号");
        Integer count = ObjectUtils.defaultIfNull(icAgreementMapper.getCurrentArchiveIncrement(incomeContract.getId()), NumberCst.ZERO);
        return StringUtils.joinWith("-", incomeContract.getArchivingCode(), count.intValue() + 1);
    }

    /**
     * 收入合同补充协议取归档编号
     * @param billCode
     * @return
     */
    private String getArchiveCodeForIncomeContract(String billCode) {
        IncomeContract entity = incomeContractMapper.selectOne(Wrappers.lambdaQuery(IncomeContract.class)
                .eq(IncomeContract::getContractCode, billCode)
                .eq(IncomeContract::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "收入合同不存在");
        if(Objects.nonNull(entity.getStarPlatformInfoId())) {
            StarPlatformInfo starPlatformInfo = starPlatformInfoMapper.selectById(entity.getStarPlatformInfoId());
            BusinessAssert.notNull(starPlatformInfo, McnErrorCode.DATA_NOT_FOUND, "红人平台信息不存在");
            if(IncomeContractTypeEnum.isLiveContract(entity.getContractType())) {
                StarArchivingCodeRule starArchivingCodeRule = ruleService.selectOne(Wrappers.lambdaQuery(StarArchivingCodeRule.class)
                        .eq(StarArchivingCodeRule::getStarId, starPlatformInfo.getStarId())
                        .eq(StarArchivingCodeRule::getIsDelete, NumberCst.ZERO));
                if(Objects.nonNull(starArchivingCodeRule)) {
                    //特殊红人取编码前缀
                    return CodeGenerateHelper.getUniqueArchivingCode(starArchivingCodeRule.getCodePrefix());
                }
                return CodeGenerateHelper.getUniqueArchivingCode(ArchiveCodeCst.CFZB);
            }
        }
        return CodeGenerateHelper.getUniqueArchivingCode(ArchiveCodeCst.CFTG);
    }

    /**
     * 年框合同补充协议取归档编号
     * @param billCode
     * @return
     */
    private String getArchiveCodeForYearFrameContract(String billCode) {
        YearFrameContract entity = yearFrameContractMapper.selectOne(Wrappers.lambdaQuery(YearFrameContract.class)
                .eq(YearFrameContract::getYearFrameCode, billCode)
                .eq(YearFrameContract::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "年框合同不存在");
        if(YearContractTypeEnum.anyMatch(entity.getContractType(), YearContractTypeEnum.LiveYearFrame)) {
            return CodeGenerateHelper.getUniqueArchivingCode(ArchiveCodeCst.ZBNK);
        } else {
            return CodeGenerateHelper.getUniqueArchivingCode(ArchiveCodeCst.TGNK);
        }
    }

    /**
     * 年框合同补充协议取归档编号
     * @param billCode
     * @return
     */
    private String getArchiveCodeForYearFrameContractAgreement(String billCode) {
        YearSupplementaryAgreement entity = yfAgreementMapper.selectOne(Wrappers.lambdaQuery(YearSupplementaryAgreement.class)
                .eq(YearSupplementaryAgreement::getAgreementCode, billCode)
                .eq(YearSupplementaryAgreement::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, "年框合同补充协议不存在");
        YearFrameContract yearFrameContract = yearFrameContractMapper.selectById(entity.getYearId());
        BusinessAssert.notNull(yearFrameContract, McnErrorCode.DATA_NOT_FOUND, "年框合同不存在");
        BusinessAssert.notBlank(yearFrameContract.getArchivingCode(), McnErrorCode.BUSINESS_ERROR, "年框合同无归档编号");
        Integer count = ObjectUtils.defaultIfNull(yfAgreementMapper.getCurrentArchiveIncrement(yearFrameContract.getId()), NumberCst.ZERO);
        return StringUtils.joinWith("-", yearFrameContract.getArchivingCode(), count + 1);
    }

    /**
     * 更新归档信息
     * @param contractCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateArchivingInfo(String contractCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        // 注意前缀开头是否存在包含关系
        if (isIncomeContractAgreement(contractCode)) {
            updateIncomeContractAgreement(contractCode, archivingStatusEnum, archivingCode);
        } else if (isIncomeContract(contractCode)) {
            updateIncomeContract(contractCode, archivingStatusEnum, archivingCode);
        } else if (isYearFrameContractAgreement(contractCode)) {
            updateYearFrameContractAgreement(contractCode, archivingStatusEnum, archivingCode);
        } else if (isYearFrameContract(contractCode)) {
            updateYearContract(contractCode, archivingStatusEnum, archivingCode);
        } else if (isPurchaseContract(contractCode)) {
            updatePurchaseContract(contractCode, archivingStatusEnum, archivingCode);
        } else if (isAnnualRebateApproval(contractCode)) {
            updateAnnualRebateApproval(contractCode, archivingStatusEnum, archivingCode);
        } else if(isStarRebateContract(contractCode)) {
            updateStarRebateContract(contractCode, archivingStatusEnum, archivingCode);
        } else {
            throw new BusinessException(McnErrorCode.ILLEGAL_BILL_CODE);
        }
    }

    /**
     * 更新客户返点合同-归档信息
     * @param contractCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateAnnualRebateApproval(String contractCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        AnnualRebateApproval before = annualRebateApprovalMapper.selectOne(Wrappers.lambdaQuery(AnnualRebateApproval.class)
                .eq(AnnualRebateApproval::getRebateContractCode, contractCode)
                .eq(AnnualRebateApproval::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该客户返点合同不存在");
        AnnualRebateApproval updateEntity = new AnnualRebateApproval();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        annualRebateApprovalMapper.updateById(updateEntity);
    }

    /**
     * 更新采购合同-归档信息
     * @param contractCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updatePurchaseContract(String contractCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        PurchaseContract before = purchaseContractMapper.selectOne(Wrappers.lambdaQuery(PurchaseContract.class)
                .eq(PurchaseContract::getContractCode, contractCode)
                .eq(PurchaseContract::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该采购合同不存在");
        PurchaseContract updateEntity = new PurchaseContract();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        purchaseContractMapper.updateById(updateEntity);
    }

    /**
     * 更新年框合同-归档信息
     * @param contractCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateYearContract(String contractCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        YearFrameContract before = yearFrameContractMapper.selectOne(Wrappers.lambdaQuery(YearFrameContract.class)
                .eq(YearFrameContract::getYearFrameCode, contractCode)
                .eq(YearFrameContract::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该年框合同不存在");
        YearFrameContract updateEntity = new YearFrameContract();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        yearFrameContractMapper.updateById(updateEntity);
        YearFrameContract after = new YearFrameContract();
        BeanUtils.copyProperties(before, after);
        after.setArchivingStatus(updateEntity.getArchivingStatus());
        after.setArchivingCode(StringUtils.defaultIfBlank(archivingCode, before.getArchivingCode()));
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(before.getId()).businessType(LogBusinessTypeEnum.YEAR_FRAME_CONTRACT).compare(before, after).build());
    }

    /**
     * 更新收入合同-归档信息
     * @param contractCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateIncomeContract(String contractCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        IncomeContract before = incomeContractMapper.selectOne(Wrappers.lambdaQuery(IncomeContract.class)
                .eq(IncomeContract::getContractCode, contractCode)
                .eq(IncomeContract::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该收入合同不存在");
        IncomeContract updateEntity = new IncomeContract();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        incomeContractMapper.updateById(updateEntity);
        IncomeContract after = new IncomeContract();
        BeanUtils.copyProperties(before, after);
        after.setArchivingStatus(updateEntity.getArchivingStatus());
        after.setArchivingCode(StringUtils.defaultIfBlank(archivingCode, before.getArchivingCode()));
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(before.getId()).businessType(LogBusinessTypeEnum.INCOME_CONTRACT).compare(before, after).build());
    }

    /**
     * 更新红人放点合同信息
     * @param contractCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateStarRebateContract(String contractCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        StarRebateContract before = starRebateContractMapper.selectOne(Wrappers.lambdaQuery(StarRebateContract.class)
                .eq(StarRebateContract::getContractCode, contractCode)
                .eq(StarRebateContract::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该红人返点合同不存在");
        StarRebateContract updateEntity = new StarRebateContract();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        starRebateContractMapper.updateById(updateEntity);
        StarRebateContract after = new StarRebateContract();
        BeanUtils.copyProperties(before, after);
        after.setArchivingStatus(updateEntity.getArchivingStatus());
        after.setArchivingCode(StringUtils.defaultIfBlank(archivingCode, before.getArchivingCode()));
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(before.getId()).businessType(LogBusinessTypeEnum.STAR_REBATE_CONTRACT).compare(before, after).build());
    }

    /**
     * 更新收入合同补充协议-归档信息
     * @param agreementCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateIncomeContractAgreement(String agreementCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        IncomeContractAgreement before = icAgreementMapper.selectOne(Wrappers.lambdaQuery(IncomeContractAgreement.class)
                .eq(IncomeContractAgreement::getAgreementCode, agreementCode)
                .eq(IncomeContractAgreement::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该收入合同补充协议不存在");
        IncomeContractAgreement updateEntity = new IncomeContractAgreement();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        icAgreementMapper.updateById(updateEntity);
        IncomeContractAgreement after = new IncomeContractAgreement();
        BeanUtils.copyProperties(before, after);
        after.setArchivingStatus(updateEntity.getArchivingStatus());
        after.setArchivingCode(StringUtils.defaultIfBlank(archivingCode, before.getArchivingCode()));
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(before.getIncomeContractId()).businessType(LogBusinessTypeEnum.INCOME_CONTRACT_AGREEMENT).compare(before, after).build());
    }

    /**
     * 更新年框合同补充协议-归档信息
     * @param agreementCode
     * @param archivingStatusEnum
     * @param archivingCode
     */
    private void updateYearFrameContractAgreement(String agreementCode, ArchivingStatusEnum archivingStatusEnum, String archivingCode) {
        YearSupplementaryAgreement before = yfAgreementMapper.selectOne(Wrappers.lambdaQuery(YearSupplementaryAgreement.class)
                .eq(YearSupplementaryAgreement::getAgreementCode, agreementCode)
                .eq(YearSupplementaryAgreement::getIsDelete, Boolean.FALSE));
        BusinessAssert.notNull(before, McnErrorCode.DATA_NOT_FOUND, "该年框合同合同补充协议不存在");
        YearSupplementaryAgreement updateEntity = new YearSupplementaryAgreement();
        updateEntity.setId(before.getId());
        updateEntity.setArchivingCode(archivingCode);
        updateEntity.setArchivingStatus(archivingStatusEnum.code());
        yfAgreementMapper.updateById(updateEntity);
        YearSupplementaryAgreement after = new YearSupplementaryAgreement();
        BeanUtils.copyProperties(before, after);
        after.setArchivingStatus(updateEntity.getArchivingStatus());
        after.setArchivingCode(StringUtils.defaultIfBlank(archivingCode, before.getArchivingCode()));
        //操作日志
        EventPublisher.post(OperateLogEvent.builder().businessId(before.getYearId()).businessType(LogBusinessTypeEnum.YEAR_SUPPLEMENTARY_AGREEMENT).compare(before, after).build());
    }


    /**
     * 是否包含收入合同
     *
     * @param contractCode 合同编号
     * @return boolean
     */
    private boolean isIncomeContract(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.INCOME_CONTRACT);
    }

    /**
     * 是否是收入合同补充协议
     * @param contractCode
     * @return
     */
    private boolean isIncomeContractAgreement(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.INCOME_CONTRACT_AGREEMENT);
    }

    /**
     * 是否包含年框合同
     *
     * @param contractCode 合同编号
     * @return boolean
     */
    private Boolean isYearFrameContract(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.YEAR_FRAME_CONTRACT);
    }

    /**
     * 是否是年框合同补充协议
     *
     * @param contractCode 合同编号
     * @return boolean
     */
    private boolean isYearFrameContractAgreement(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.YEAR_FRAME_AGREEMENT);
    }

    /**
     * 是否包含采购合同
     *
     * @param contractCode 合同编号
     * @return boolean
     */
    private boolean isPurchaseContract(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.PURCHASE_CONTRACT);
    }


    /**
     * 是否包含客户返点合同
     *
     * @param contractCode 合同编号
     * @return boolean
     */
    private boolean isAnnualRebateApproval(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.ANNUAL_REBATE_APPROVAL);
    }

    /**
     * 是否是红人返点合同
     *
     * @param contractCode 合同编号
     * @return boolean
     */
    private boolean isStarRebateContract(String contractCode) {
        return StringUtils.startsWith(contractCode, BillCodeCst.STAR_REBATE_APPROVAL);
    }
}
